package com.zhangxu.microservice.auth.biz.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zhangxu.microservice.auth.biz.dto.AssignRoleDTO;
import com.zhangxu.microservice.auth.biz.dto.EmployeeRoleDTO;
import com.zhangxu.microservice.auth.biz.mapstruct.EmployeeRoleConverter;
import com.zhangxu.microservice.auth.biz.service.EmployeeRoleService;
import com.zhangxu.microservice.auth.dao.condition.EmployeeRoleCondition;
import com.zhangxu.microservice.auth.dao.entity.EmployeeRoleDO;
import com.zhangxu.microservice.auth.dao.entity.RoleDO;
import com.zhangxu.microservice.auth.dao.service.EmployeeRoleDao;
import com.zhangxu.microservice.auth.dao.service.RoleDao;
import com.zhangxu.microservice.auth.facade.service.EmployeeFacadeService;
import com.zhangxu.microservice.common.exception.BizException;
import com.zhangxu.microservice.common.utils.AssertUtils;
import com.zhangxu.microservice.common.utils.ListUtils;
import com.zhangxu.microservice.employee.api.response.EmployeeApiDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 员工角色关系服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EmployeeRoleServiceImpl implements EmployeeRoleService {

    private final EmployeeRoleDao employeeRoleDao;
    private final EmployeeRoleConverter employeeRoleConverter;
    private final RoleDao roleDao;
    private final EmployeeFacadeService employeeFacadeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignRoles(AssignRoleDTO assignRoleDTO) {
        Long employeeId = assignRoleDTO.getEmployeeId();
        List<Long> roleIds = assignRoleDTO.getRoleIds();

        // 先删除该员工的所有角色关系
        employeeRoleDao.deleteByEmployeeId(employeeId);

        // 如果角色列表不为空，则添加新的角色关系
        if (!CollectionUtils.isEmpty(roleIds)) {
            List<EmployeeRoleDO> employeeRoleDOList = roleIds.stream().map(roleId -> {
                EmployeeRoleDO employeeRoleDO = new EmployeeRoleDO();
                employeeRoleDO.setEmployeeId(employeeId);
                employeeRoleDO.setRoleId(roleId);
                employeeRoleDO.setDeleteTime(0L);
                return employeeRoleDO;
            }).collect(Collectors.toList());
            employeeRoleDao.saveBatch(employeeRoleDOList);
        }
    }

    @Override
    public Long addEmployeeRole(Long employeeId, Long roleId) {
        // 检查关系是否已存在
        EmployeeRoleDO existingRelation = employeeRoleDao.getByEmployeeIdAndRoleId(employeeId, roleId);
        if (existingRelation != null) {
            throw new BizException("员工角色关系已存在");
        }

        EmployeeRoleDO employeeRoleDO = new EmployeeRoleDO();
        employeeRoleDO.setEmployeeId(employeeId);
        employeeRoleDO.setRoleId(roleId);
        employeeRoleDO.setDeleteTime(0L);
        employeeRoleDao.save(employeeRoleDO);
        return employeeRoleDO.getId();
    }

    @Override
    public void deleteEmployeeRole(Long id) {
        EmployeeRoleDO existingRelation = employeeRoleDao.getById(id);
        AssertUtils.notNull(existingRelation, "员工角色关系不存在");

        // 逻辑删除
        EmployeeRoleDO employeeRoleDO = new EmployeeRoleDO();
        employeeRoleDO.setId(id);
        employeeRoleDO.setDeleteTime(System.currentTimeMillis());
        employeeRoleDao.updateById(employeeRoleDO);
    }

    @Override
    public void deleteEmployeeRoleByIds(Long employeeId, Long roleId) {
        EmployeeRoleDO existingRelation = employeeRoleDao.getByEmployeeIdAndRoleId(employeeId, roleId);
        if (existingRelation != null) {
            deleteEmployeeRole(existingRelation.getId());
        }
    }

    @Override
    public void deleteByEmployeeId(Long employeeId) {
        employeeRoleDao.deleteByEmployeeId(employeeId);
    }

    @Override
    public void deleteByRoleId(Long roleId) {
        employeeRoleDao.deleteByRoleId(roleId);
    }

    @Override
    public List<EmployeeRoleDTO> getByEmployeeId(Long employeeId) {
        List<EmployeeRoleDO> employeeRoleDOList = employeeRoleDao.getByEmployeeId(employeeId);
        return employeeRoleDOList.stream()
                .map(employeeRoleConverter::toEmployeeRoleDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<EmployeeRoleDTO> getByRoleId(Long roleId) {
        List<EmployeeRoleDO> employeeRoleDOList = employeeRoleDao.getByRoleId(roleId);
        return employeeRoleDOList.stream()
                .map(employeeRoleConverter::toEmployeeRoleDTO)
                .collect(Collectors.toList());
    }

    @Override
    public IPage<EmployeeRoleDTO> employeeRolePage(EmployeeRoleCondition condition) {
        IPage<EmployeeRoleDO> page = employeeRoleDao.page(condition);
        //开始转换，角色名称
        List<EmployeeRoleDO> records = page.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            //获取角色ID
            List<Long> roleIds = ListUtils.mapDistinctList(records, EmployeeRoleDO::getRoleId);
            List<RoleDO> roleDOS = roleDao.listByIds(roleIds);
            Map<Long, String> roleMap = ListUtils.toMap(roleDOS, RoleDO::getId, RoleDO::getName);

            //员工名称
            List<Long> employeeIds = ListUtils.mapDistinctList(records, EmployeeRoleDO::getEmployeeId);
            List<EmployeeApiDTO> employeeApiDTOS = employeeFacadeService.listEmployeeByIds(employeeIds);
            Map<Long, EmployeeApiDTO> employeeApiDTOMap = ListUtils.toMap(employeeApiDTOS, EmployeeApiDTO::getId);
            return page.convert(employeeRoleDO -> {
                EmployeeRoleDTO employeeRoleDTO = employeeRoleConverter.toEmployeeRoleDTO(employeeRoleDO);
                employeeRoleDTO.setRoleName(roleMap.get(employeeRoleDO.getRoleId()));
                employeeRoleDTO.setEmployeeName(Optional.ofNullable(employeeApiDTOMap.get(employeeRoleDO.getEmployeeId())).map(EmployeeApiDTO::getName).orElse(null));
                return employeeRoleDTO;
            });
        }
        return page.convert(employeeRoleConverter::toEmployeeRoleDTO);
    }
}